using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using LuaInterface;

public class NetworkManager {

	static NetworkManager _instance;
	public static NetworkManager Instance {
		get {
			if (_instance == null) _instance = new NetworkManager();
			return _instance;
		}
	}

	private SocketClient _socketClient = null;
	private SocketConfig _socketCfg = null;
	ConnectStatus _lastStatus = ConnectStatus.None;	// 上一次的SocketClient状态


	public NetworkManager(){
		_socketClient = new SocketClient ();
	}

	public int GetRpcKey(string name)
	{
		return _socketCfg.getRpcKey(name); 
	}

	public void InitSocketJson(string str)
	{
		_socketCfg = Util.Json2Object<SocketConfig>(str); //解析成SocketConfig

		_socketCfg.cacheRpcName(); 

		//Debug.Log(str);
		//string[] netWorkEvent = new string[3]{"OnConnect","OnException","OnDisconnect"};

		// for (int i = 0; i < 3; i++)
		// {
		// 	SocketFunction socketFun = new SocketFunction();
		// 	socketFun.function_name = netWorkEvent[i];
		// 	string key = (100 + i + 1).ToString();
		// 	if (_socketCfg.function_cfg.ContainsKey (key))
		// 	{
		// 		_socketCfg.function_cfg.Remove(key);
		// 	}
		// 	_socketCfg.function_cfg.Add(key, socketFun);
		// }
	}

	public void Update()
	{
		HandleSocketClientMessage();
		CheckConnectStatus();
    }

	// 处理SocketClient收到的消息
	private void HandleSocketClientMessage()
	{
		ByteBuffer[] buffers = _socketClient.FetchReceivedMessage();
        if (buffers == null) return;

		foreach (ByteBuffer buff in buffers)
		{
			// col:发送到lua层的代码嵌合在解包逻辑中不好分割, 之后再分割
            int key = buff.ReadShort();
            RpcEncoder.Decode(_socketCfg, key, buff);

			// RecvRpc

		}
	}

	// 检查SocketClient的运行状态
	private void CheckConnectStatus()
	{
        ConnectStatus newStatus = _socketClient.GetStatus();
		if (newStatus != _lastStatus) {
			// 触发新状态
			GameManager.CallLuaFunction("OnConnectStatus", (int)newStatus, GetError());

			_lastStatus = newStatus;
		}
	}

	// 发送消息
	public void SendRpc(int key, LuaTable args)
	{
		// 序列化
		ByteBuffer buff = RpcEncoder.Encode(_socketCfg, key, args);
		args.Dispose(); // col:??

		// 发送
		_socketClient.Write(buff.ToBytes());
	}

	// cs 层手动封包数据发送
	public void SendRpcBuff(ByteBuffer buff)
	{
		_socketClient.Write(buff.ToBytes());
	}

	// // 处理接收消息
	// private void RecvRpc()
	// {
	// 	GameManager.Instance.CallLuaFunction();
	// }

	// 连接服务器
	public void Connect(string ip, int port)
	{
		_socketClient.Connect(ip, port);
	}

    // 断开连接
    public void Disconnect()
    {
        if (_socketClient.Connected()) {
            _socketClient.Disconnect();
        }
    }

	// 是否在连接状态
    public bool Connected() {
        return _socketClient.Connected();
    }

	// 获取错误
	public string GetError() {
    	return _socketClient.GetError();
    }


/*
	//协议解包
	public void UnPackRpc(int key, ByteBuffer value) {
		SocketFunction socketFun = _socketCfg.getSocketFun(key);
  		if (socketFun == null)
  		{
  			Debugger.LogWarning("协议解包异常：receive unknown packet:" + key);
  			return;
  		}else{
  			//Debug.Log("ParseValue: " + socketFun.function_name);
  		}

		_unPackBuffer = value;

  		LuaState luaState = LuaEngine.GetMainState();
  		int oldTop = luaState.LuaGetTop();//获取当前的堆栈位置

  		try
  		{
  			luaState.LuaGetGlobal("OnSocket");//获取方法名
  			LuaPush(socketFun.function_name);
  			LuaCreateTable();//封装的table
  			
  			int argsLens = socketFun.args.Count;
  			
  			for (int i = 0; i < argsLens; i++)
  			{
  				LuaPush((i + 1));//push进去key,lua中的key从1开始
  				SocketFunctionArgs argInfo = socketFun.args[i];
  				if (argInfo.class_index != -1)
  				{
  					UnPackStruct(argInfo.class_index, argInfo.type);
  				}
  				else
  					UnPackBaseType(argInfo.type);
  			}
  			
  			luaState.PCall(2, oldTop);//两个参数，一个协议号，一个table
  			luaState.LuaSetTop(oldTop);//重置堆栈位置
  		}catch(Exception e)
  		{
  			luaState.LuaSetTop(oldTop);//重置堆栈位置
  			//throw e;
  			GameManager.Instance.AsyncActionScheduler.EnqueueAction (ThreadSafeLogger.ThreadSafeLog, "协议解包异常：" + e.ToString(), ThreadSafeLogType.Error);
  		}
		_unPackBuffer.Close();
		_unPackBuffer = null;
	}

	private void LuaSetTable()
  	{
  		LuaEngine.GetMainState().LuaSetTable(-3);
  	}

  	private void LuaCreateTable()
  	{
  		LuaEngine.GetMainState().LuaCreateTable();
  	}
  	
	private void LuaPush(object value)
  	{
  		LuaEngine.GetMainState().Push(value);
  	}

	private void UnPackStruct(int index, int btype)
	{
		int type = (btype < SocketConfig.ARRAY_VAR) ? btype : btype - SocketConfig.ARRAY_VAR;
  		bool isArray = btype >= SocketConfig.ARRAY_VAR;
  		int arrayCount = 0;
  		if (isArray) //如果是数组类型
			arrayCount = _unPackBuffer.ReadInt();
  		else
  			arrayCount = 1;//默认为1
		
  		SocketClass structs = _socketCfg.getSocketClass(index);
  		List<SocketClassField> fieldList = structs.field;
  		//int fieldLens = fieldList.Count;
		
  		if (isArray)//这里如果是数组，才要封装多一层
  		{
  			LuaCreateTable();
  			for (int i = 0; i < arrayCount;i++ )
  			{
  				LuaPush(i + 1);
  				UnPackStructItem(fieldList);
  			}
  			LuaSetTable();//如果是数组才需要设置堆栈
  		}else
	  	{
  			UnPackStructItem(fieldList);
  		}
	}

	private void UnPackStructItem(List<SocketClassField> fieldList)
	{
		LuaCreateTable();
		int fieldLens = fieldList.Count;
		for (int j = 0; j < fieldLens; j++)
		{
			SocketClassField fieldInfo = fieldList[j];
			LuaPush(fieldInfo.field_name);
			if (fieldInfo.class_index != -1) {
				UnPackStruct (fieldInfo.class_index, fieldInfo.type);
			} else {
				UnPackBaseType (fieldInfo.type);
			}
		}
		LuaSetTable();
	}

	private void UnPackBaseType(int btype)
	{
		int type = (btype < SocketConfig.ARRAY_VAR) ? btype : btype - SocketConfig.ARRAY_VAR;
		bool isArray = btype >= SocketConfig.ARRAY_VAR;
		int arrayCount = 0;
		if (isArray) //如果是数组类型
			arrayCount = _unPackBuffer.ReadInt();
		else
			arrayCount = 1;//默认为1
		
		if (isArray)
		{
			LuaCreateTable();
			for (int i = 0; i < arrayCount;i++ )
			{
				LuaPush(i + 1);
				UnPackBaseValue(type);
				LuaSetTable();
			}
		}else
		{
			UnPackBaseValue(type);
		}
		LuaSetTable();
	}

	private void UnPackBaseValue(int btype)
	{
		object data = null;
		switch(btype)
		{
		case SocketConfig.TYPE_INT: 
			data = _unPackBuffer.ReadInt();
			break;
		case SocketConfig.TYPE_STRING: 
			data = _unPackBuffer.ReadLongString();
			break;
		case SocketConfig.TYPE_BUFF: 
			data = _unPackBuffer.ReadLongString();
			break;
		case SocketConfig.TYPE_DOUBLE: 
			data = _unPackBuffer.ReadDouble();
			break;
		case SocketConfig.TYPE_INT8: 
			data = _unPackBuffer.ReadByte();
			break;
		case SocketConfig.TYPE_INT16: 
			data = _unPackBuffer.ReadShort();
			break;
		case SocketConfig.TYPE_FLOAT: 
			data = _unPackBuffer.ReadFloat();
			break;
		default:
			Debug.Assert(false,"协议解包异常：unsupport data type for parse type=" + btype);
			break;
		}
		LuaPush(data);
	}

	//协议封包
	public void PackRpc(int key, LuaTable args)
	{
		SocketFunction socketFun = _socketCfg.getSocketFun(key);

		string functionName = socketFun.function_name;//协议 名字
		int argsLen = args.Length; //获取参数长度
		int rpcArgsLen = socketFun.args.Count;//协议参数长度

		Debug.Assert(argsLen == rpcArgsLen, string.Format("协议封包异常：{0} args count error", functionName));//参数个数不正确

		_packBuffer = new ByteBuffer();//二进制流

		_packBuffer.WriteShort((short)key);//写入协议号，目前协议号是16位的

		for (int i = 0; i < rpcArgsLen; i++ )
		{
			SocketFunctionArgs argInfo = socketFun.args[i];
			object arg = args[i + 1];//lua从1开始的
			Debug.Assert(arg != null, string.Format("协议封包异常：fun {0} arg {1} is nil", functionName, i + 1));
			if (argInfo.class_index != -1)//这是一个类
			{
				PackStruct((LuaTable)arg, argInfo.class_index, argInfo.type);
			}else
			{
				PackBaseType(arg, argInfo.type);
			}
		}
		SendMessage(_packBuffer);
		args.Dispose();
		args = null;
		_packBuffer = null;
	}

	private void PackStruct(LuaTable value, int index, int btype)
	{
		int type = (btype < SocketConfig.ARRAY_VAR) ? btype : btype - SocketConfig.ARRAY_VAR;
		bool isArray = btype >= SocketConfig.ARRAY_VAR;

		SocketClass structs = _socketCfg.getSocketClass(index);
		List<SocketClassField> fieldList = structs.field;
		//int fieldLens = fieldList.Count;

		if (isArray)//这里如果是数组，才要封装多一层
		{
			int arrayCount = value.Length;
			_packBuffer.WriteInt(arrayCount);
			for (int i = 0; i < arrayCount;i++ )
			{
				PackStructItem(fieldList, (LuaTable)value[i + 1]);
			}
		}else
		{
			PackStructItem(fieldList, value);
		}
	}

	private void PackStructItem(List<SocketClassField> fieldList, LuaTable value)
	{
		int fieldLens = fieldList.Count;
		for (int j = 0; j < fieldLens; j++)
		{
			SocketClassField fieldInfo = fieldList[j];
			string fieldName = fieldInfo.field_name;
			object fieldValue;
			if (value[j + 1] != null)//lua从1开始的啊
				fieldValue = value[j + 1];
			else
				fieldValue = value[fieldName];
			if (fieldInfo.class_index != -1) {
				PackStruct ((LuaTable)fieldValue, fieldInfo.class_index, fieldInfo.type);
			} else {
				PackBaseType (fieldValue, fieldInfo.type);
			}
		}
	}

	private void PackBaseType(object value, int btype)
	{
		int type = (btype < SocketConfig.ARRAY_VAR) ? btype : btype - SocketConfig.ARRAY_VAR;
		bool isArray = btype >= SocketConfig.ARRAY_VAR;

		if (isArray)//如果是数组
		{
			LuaTable table = (LuaTable)value;
			int valueLen = table.Length;
			_packBuffer.WriteInt(valueLen);//写入长度
			for(int i = 0;i<valueLen;i++)
			{
				PackBaseValue(type, table[i + 1]);//lua从1开始
			}
		}else
		{
			PackBaseValue(type, value);
		}
	}

	private void PackBaseValue(int btype, object value)
	{
		switch(btype)
		{
		case SocketConfig.TYPE_INT: 
			_packBuffer.WriteInt(Convert.ToInt32(value));
			break;
		case SocketConfig.TYPE_STRING: 
			_packBuffer.WriteString(Convert.ToString (value));
			break;
		case SocketConfig.TYPE_BUFF: 
			_packBuffer.WriteString (Convert.ToString (value));
			break;
		case SocketConfig.TYPE_DOUBLE: 
			_packBuffer.WriteDouble(Convert.ToDouble(value));
			break;
		case SocketConfig.TYPE_INT8: 
			_packBuffer.WriteByte(Convert.ToSByte(value));
			break;
		case SocketConfig.TYPE_INT16: 
			_packBuffer.WriteShort(Convert.ToInt16(value));
			break;
		case SocketConfig.TYPE_FLOAT: 
			_packBuffer.WriteFloat(Convert.ToSingle(value));
			break;
		default:
			Debug.Assert(false, "协议封包异常：pack base type args unsupport"); //不支持的输出类型
			break;
		}
	}

	*/

  //   public void Logout() {
  //       SocketClient.Logout();
  //   }

  //   public void SendConnect(string addr, int port) {
  //       SocketClient.SendConnect(addr, port);
  //   }
	
  //   public void SendMessage(ByteBuffer buffer) {
		// SocketClient.SendMessage(buffer);
  //   }

  //   public bool IsConnectSuccess() {
  //       return SocketClient.ConnectSuccess();
  //   }

  //   public string GetErrorMsg() {
  //       return SocketClient.GetErrorMsg();
  //   }
	
}
